package com.androdro.bluenote.coolstruttin1588;
/**
 * Cool Struttin'
 * SippinAtBells.java
 *
 * @author Hiroaki Sakuma <sakuma@androdro.com>
 * @version $Id$
 *
 * Copyright (C) androdro lab. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of the nor the names of its contributors may be used to
 *   endorse or promote products derived from this software without specific
 *   prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 *
 */

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import android.view.View;
import com.androdro.bluenote.coolstruttin1588.exception.*;
import com.androdro.bluenote.coolstruttin1588.utility.Define;

/*
 ** DecryptAES
 */
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;

/*
 ** Infoticker
 */
import java.util.Random;
import android.graphics.Color;
import android.os.Handler;
import android.text.Html;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import org.json.JSONArray;
import org.json.JSONObject;


public class SippinAtBells {

	/**
   *
   */

	private static SippinAtBells me = null;
	private static SippinAtBells.Factory factory = null;


	private SippinAtBells() {
	}


	public static SippinAtBells getInstance() {
		if (me == null) {
			me = new SippinAtBells();
		}
		return me;
	}


	public static void halt() {
		if (me != null) {
			if (factory != null) {
				factory.halt();
				factory = null;
			}
			me = null;
		}
	}


	public SippinAtBells.Factory getFactory() {
		if (factory == null) {
			factory = new SippinAtBells.Factory();
		}
		return factory;
	}


	public class Factory {


		SippinAtBells.PageManager pagemanager;
		SippinAtBells.Infoticker info;


		private Factory() {
		}


		public void halt() {
			if (this.info != null) {
				this.info.halt();
			}
		}


		public SippinAtBells.Status generateStatus(Integer status, String mapname, String name) {
			return new Status(status, mapname, name);
		}


		public SippinAtBells.Status generateStatus(Integer status, String name) {
			return new Status(status, name);
		}


		public SippinAtBells.Status generateStatus(Integer status) {
			return new Status(status);
		}


		public SippinAtBells.Status generateStatus() {
			return new Status();
		}


		public SippinAtBells.PageManager getPageManager() {
			if (this.pagemanager == null) {
				this.pagemanager = new PageManager();
			}
			return this.pagemanager;
		}


		public SippinAtBells.DecryptAES getDecryptor() {
			return new DecryptAES();
		}


		public SippinAtBells.Infoticker getInfoticker(CoolStruttin root) {
			if (this.info == null) {
				this.info = new Infoticker(root);
			}
			return this.info;
		}


	}


	public class Status {


		private HashMap<String, Object> d;


		private Status() {
			this.d = new HashMap<String, Object>();
		}

		private Status(Integer status, String mapname, String name) {
			this();
			this.d.put("status", status);
			this.d.put("mapname", mapname);
			this.d.put("name", name);
		}


		private Status(Integer status, String name) {
			this();
			this.d.put("status", status);
			this.d.put("name", name);
		}


		private Status(Integer status) {
			this();
			this.d.put("status", status);
		}


		public String getName() {
			return (String)this.d.get("name");
		}


		public String getMapname() {
			return (String)this.d.get("mapname");
		}


		public Integer getStatus() {
			return (Integer)this.d.get("status");
		}


	}


	public class PageManager {


		private ArrayList<HashMap<String, Object>> pagestack;


		private PageManager() {
			this.pagestack = new ArrayList<HashMap<String, Object>>();
		}


		public View newPage(HashMap<String, Object> actionmap) {

			HashMap<String, Object> lastactionmap;

			this.pagestack.add(actionmap);

			try {
				lastactionmap = getPrevPage();
				if (!lastactionmap.get("view").equals(actionmap.get("view"))) {
					this.pagestack.add(actionmap);
				}
			} catch (SippinAtBells.YouAreIntroException yaie) {
			} catch (SippinAtBells.ThisIsIntroException tiie) {
				this.pagestack.clear();
				this.pagestack.add(actionmap);
			}


System.out.println(this.pagestack);

			return (View)actionmap.get("view");

		}


		public View newPage(Integer action, View view, String mapname) {

			HashMap<String, Object> actionmap = new HashMap<String, Object>();
			actionmap.put("action", action);
			actionmap.put("view", view);
			actionmap.put("mapname", mapname);

			return newPage(actionmap);

		}


		public HashMap<String, Object> getCurrentPage() {

			int lastaction = this.pagestack.size() - 1;
			HashMap<String, Object> actionmap = this.pagestack.get(lastaction);

			return actionmap;

		}


		public Integer getCurrentPageAction() {
			return (Integer)getCurrentPage().get("action");
		}


		public View getCurrentPageView() {
			return (View)getCurrentPage().get("view");
		}


		public HashMap<String, Object> getPrevPage() {

			int lastaction = this.pagestack.size() - 1;

			if (lastaction < 0) {
				throw new YouAreIntroException();
			}
			if (lastaction == 0 || this.pagestack.get(lastaction).get("action").equals(Define.ACTION.ACTION_INTRO)) {
				throw new ThisIsIntroException(this.pagestack.get(lastaction));
			}

			this.pagestack.remove(lastaction);
			int prevaction = lastaction - 1;

			HashMap<String, Object> actionmap = this.pagestack.get(prevaction);

			return actionmap;

		}


		public View getPrevPageView() {
			return (View)getPrevPage().get("view");
		}


	}


	public class PageManagerException
		extends
			CoolStruttin1588RuntimeException {


		/**
		 *
		 */
		HashMap<String, Object> actionmap = new HashMap<String, Object>();


		public PageManagerException() {
			super();
		}


		public PageManagerException(HashMap<String, Object> actionmap) {
			super();
			this.actionmap = actionmap;
		}


		public HashMap<String, Object> getActionmap() {
			return this.actionmap;
		}


	}


	public class YouAreIntroException
		extends
			PageManagerException {


		/**
		 *
		 */

		public YouAreIntroException() {
			super();
		}


	}


	public class ThisIsIntroException
		extends
			PageManagerException {


		/**
		 *
		 */


		public ThisIsIntroException() {
			super();
		}


		public ThisIsIntroException(HashMap<String, Object> actionmap) {
			super(actionmap);
		}


	}


	public class DecryptAES {


		private DecryptAES() {
		}


		public String decrypt(byte[] enc, String keyString) {

			byte[] salt = new byte[8];
			byte[] cipherText;
			String plainText;
			SecretKeySpec key;
			IvParameterSpec param;
			MessageDigest md;
			byte rawKey[] = new byte[16];
			byte iv[] = new byte[16];
			byte dk[];


			try {

				md = MessageDigest.getInstance("MD5");

				for (int i = 0; i < 8; i++) {
					salt[i] = enc[8 + i];
				}
				cipherText = new byte[enc.length - 16];
				for (int i = 0; i < enc.length - 16; i++) {
					cipherText[i] = enc[16 + i];
				}
				Cipher cbc = Cipher.getInstance("AES/CBC/PKCS5Padding");

				int keyLen = rawKey.length;
				int ivLen = cbc.getBlockSize();
				int hashLen = md.getDigestLength();
				dk = new byte[keyLen + ivLen];

				int pos = 0;
				while (pos < dk.length) {
					md.update(dk, 0, pos);
					md.update(keyString.getBytes("UTF-8"));
					md.update(salt);
					md.digest(dk, pos, hashLen);
					pos += hashLen;
				}

				for (int i = 0; i < keyLen; i++) {
					rawKey[i] = dk[i];
				}

				for (int i = 0; i < ivLen; i++) {
					iv[i] = dk[keyLen + i];
				}

				key = new SecretKeySpec(rawKey, "AES");
				param = new IvParameterSpec(iv);
				cbc.init(Cipher.DECRYPT_MODE, key, param);
				plainText = new String(cbc.doFinal(cipherText, 0, cipherText.length));

			} catch (Exception e) {
				e.printStackTrace();
				plainText = "";
			}

			return plainText;

		}

	}


	public class Infoticker
		extends
			LinearLayout
		implements
			View.OnClickListener,
			Runnable {


		Thread t;
		CoolStruttin root;
		boolean halt = false;
		Map<String, String> info;
		ArrayList<String> loading;


		private Infoticker(CoolStruttin root) {

			super(root);
			this.root = root;

			setOrientation(LinearLayout.HORIZONTAL);
			setGravity(Gravity.BOTTOM);

			TextView info = new TextView(this.root);
			info.setText(Html.fromHtml(
				"<font color=\"#ff7f00\" face=\"sans-serif\">Loading...</font>"
			));
			info.setBackgroundColor(Color.BLACK);
			info.setGravity(Gravity.LEFT & Gravity.CENTER_VERTICAL);
			info.setOnClickListener(this);


			addView(info, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 30));

//			ProgressBar progress = new CoolStruttinProgressBar(this.root, null, android.R.attr.progressBarStyle, android.R.style.Widget_ProgressBar_Small);

/*
			TypedArray a = context.obtainStyledAttributes(new int [] { android.R.attr.progressBarStyle });
			System.out.println(a);

			AttributeSet attrs = this.root.getResources().getLayout(R.id.progressbar);
			System.out.println(attrs.getAttributeCount());
			ProgressBar progress = new ProgressBar(this.root, attrs);
			try {
//			this.root.setContentView(R.layout.progressbar);
//			ProgressBar progress = (ProgressBar)this.root.findViewById(R.id.progressbar);
//			progress.setProgressDrawable(this.root.getResources().getDrawable(android.R.drawable.progress_small));
			System.out.println(this.root.getResources().getLayout(R.layout.progressbar));
			progress.setProgressDrawable(this.root.getResources().getDrawable(R.drawable.spinner_black_16));
			progress.setIndeterminate(true);
			addView(progress, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
			} catch (Exception e) {
				e.printStackTrace();
			}
*/

			loading = new ArrayList<String>();


			if (this.t == null) {
				this.t = new Thread(this);
			}
			this.t.start();


		}


		public FrameLayout.LayoutParams getLayoutParams() {
			return new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
		}


		public void halt() {
			this.halt = true;
		}


		public void run() {

			long time = 0;
			Thread t = Thread.currentThread();

			try {

				ArrayList<HashMap<String, String>> informations = new ArrayList<HashMap<String, String>>();
				JSONObject config = this.root.getConfig();

				JSONArray ia = config.getJSONObject("Body").getJSONArray("Informations");
				int l = ia.length();

				for (int i = 0; i < l; i++) {
					HashMap<String, String> information = new HashMap<String, String>();
					information.put("title", ia.getJSONObject(i).getString("title"));
					information.put("url", ia.getJSONObject(i).getString("url"));
					informations.add(information);
				}

				final View dummy = new View(this.root);
				dummy.setBackgroundColor(Color.BLACK);


				for (int i = (new Random()).nextInt(l - 1); !this.halt; i++) {

					time = System.currentTimeMillis();


					this.info = informations.get(i % l);

					final TextView info = new TextView(this.root);
					info.setText(Html.fromHtml(
						"<font color=\"#ff7f00\" face=\"sans-serif\">" + this.info.get("title") + "</font>"
					));
					info.setBackgroundColor(Color.BLACK);
					info.setGravity(Gravity.LEFT & Gravity.CENTER_VERTICAL);
					info.setOnClickListener(this);

					synchronized(this.t) {

						this.root.post(
							new Runnable() {
								public void run() {
									removeViewAt(0);
									addView(dummy, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 30));
								}
							}
						);

						t.notify();
					} //synchronized

					Thread.sleep(250);

					synchronized(this.t) {

						this.root.post(
							new Runnable() {
								public void run() {
									removeViewAt(0);
									addView(info, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 30));
								}
							}
						);

					} //synchronized

					for (; System.currentTimeMillis() < time + 10 * 1000 && !this.halt; ) {
						synchronized(this.t) {

/*
							if (loading.size() > 0) {

								final TextView load = new TextView(this.root);
								load.setText(Html.fromHtml(
									"<font color=\"#ff7f00\" face=\"sans-serif\">" + loading.get(0) + "</font>"
								));
								load.setBackgroundColor(Color.BLACK);
								load.setGravity(Gravity.LEFT & Gravity.CENTER_VERTICAL);

								this.root.post(
									new Runnable() {
										public void run() {
											removeViewAt(0);
											addView(load, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 30));
										}
									}
								);

							} else {

								this.root.post(
									new Runnable() {
										public void run() {
											removeViewAt(0);
											addView(info, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 30));
										}
									}
								);

							}
*/

							t.notify();
						} //synchronized
						Thread.sleep(250);

					}

					if (i % l == 0) {
						i = 0;
					}

				} //for

			} catch (Exception e) {
				e.printStackTrace();
			}

		}


		public void onClick(View v) {

			this.root.post(
				new Runnable() {
					public void run() {
						root.go(Define.ACTION.ACTION_INFO, info.get("url"));
					}
				}
			);

		}


	}


}
